

#include <string.h>

#include "../../common/log.h"
#include "tcp_buffer.h"

namespace rocket {

TcpBuffer::TcpBuffer(int size) : m_size(size) {
    DEBUGLOG("buffer init %d", m_size);
    m_buffer.resize(m_size);
    memset(&m_buffer[0], 0, m_size);
};

TcpBuffer::~TcpBuffer() {}

int TcpBuffer::readable() { return m_write_index - m_read_index; }

int TcpBuffer::writable() { return m_size - m_write_index; }

int TcpBuffer::readIndex() { return m_read_index; }

int TcpBuffer::writeIndex() { return m_write_index; }

void TcpBuffer::writeToBuffer(const char *buf, int size) {
    if (size > writable()) {
        // Resize the buffer.
        int new_size = 2 * (m_write_index + size);
        resizeBuffer(new_size);
    }
    memcpy(&m_buffer[m_write_index], buf, size);
    m_write_index += size;
};

void TcpBuffer::readFromBuffer(std::vector<char> &re, int size) {
    if (readable() == 0) {
        return;
    }

    int read_size = readable() > size ? size : readable();

    std::vector<char> tmp(read_size);
    memcpy(&tmp[0], &m_buffer[m_read_index], read_size);

    re.swap(tmp);
    m_read_index += read_size;

    adjustBuffer();
}

void TcpBuffer::resizeBuffer(int new_size) {
    DEBUGLOG("started to resize buffer from %d to %d", m_size, new_size);
    std::vector<char> tmp(new_size);
    int count = std::min(new_size, readable());
    memcpy(&tmp[0], &m_buffer[m_read_index], count);
    m_buffer.swap(tmp);

    m_read_index = 0;
    m_write_index = m_read_index + count;
    m_size = new_size;
}

void TcpBuffer::adjustBuffer() {
    if (m_read_index < m_size / 3) {
        return;
    }
    std::vector<char> buffer(m_buffer.size());
    int count = readable();
    memcpy(&buffer[0], &m_buffer[m_read_index], count);
    m_buffer.swap(buffer);
    m_write_index -= m_read_index;
    m_read_index = 0;

    buffer.clear();
}

void TcpBuffer::moveReadIndex(int size) {
    int new_read_index = m_read_index + size;
    if (new_read_index > m_size) {
        ERRORLOG("move readIndex error, invalid move %d, old_read_index %d, "
                 "buffer size %d",
                 size, m_read_index, m_size);
        return;
    }
    m_read_index = new_read_index;
    adjustBuffer();
}

void TcpBuffer::moveWriteIndex(int size) {
    int new_write_index = m_write_index + size;
    if (new_write_index > m_size) {
        ERRORLOG("move writeIndex error, invalid move %d, old_write_index %d, "
                 "buffer size %d",
                 size, m_write_index, m_size);
        return;
    }
    m_write_index = new_write_index;
}
} // namespace rocket
